package com.example.block_chain.service.impl.blockChain;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.block_chain.common.BlockParameters;
import com.example.block_chain.common.SystemParameters;
import com.example.block_chain.domain.dto.BlockDto;
import com.example.block_chain.domain.pbft.VoteEnum;
import com.example.block_chain.domain.pbft.VoteInfo;
import com.example.block_chain.domain.pojo.Award;
import com.example.block_chain.domain.pojo.Block;
import com.example.block_chain.mapper.BlockMapper;
import com.example.block_chain.service.blockChain.BlockService;
import com.example.block_chain.service.faculty.FacultyService;
import com.example.block_chain.service.major.MajorService;
import com.example.block_chain.utils.KeyValueReaderUtil;
import com.example.block_chain.utils.MerkelTreeNodeUtil;
import com.example.block_chain.utils.SimpleMerkleTree;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;

/*
 *@description: 区块业务实现类
 *@author: hisen
 *@Time: 2023/11/12  17:35
 */
@Service
public class BlockServiceImpl extends ServiceImpl<BlockMapper, Block> implements BlockService {

    @Resource
    FacultyService facultyService;

    @Resource
    MajorService majorService;

    @Override
    public VoteInfo createSchoolBlock(String schoolCode) {
        Block block = new Block();
        //创建学校区块
        block.setType(BlockParameters.SCHOOL_BLOCK_TYPE);
        block.setCode(schoolCode);
        block.setDigest(KeyValueReaderUtil.getDigestByCode(schoolCode, SystemParameters.SCHOOL_FILE_PATH));
        block.setPreHash(getById(BlockParameters.GENESIS_BLOCK_ID).getMerkleHash());
        return getVoteInfo(block);
    }

    @Override
    public VoteInfo createFacultyBlock(String schoolCode, String facultyCode) {
        //创建学院区块
        Block block = new Block();
        block.setType(BlockParameters.FACULTY_BLOCK_TYPE);
        block.setDigest(facultyService.getFaculty(facultyCode).getName());
        block.setCode(facultyCode);
        LambdaQueryWrapper<Block> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Block::getType, BlockParameters.SCHOOL_BLOCK_TYPE);
        wrapper.eq(Block::getCode, schoolCode);
        block.setPreHash(getOne(wrapper).getMerkleHash());
        return getVoteInfo(block);
    }

    @Override
    public VoteInfo createMajorBlock(String facultyCode, String majorCode) {
        Block block = new Block();
        //创建专业区块
        block.setType(BlockParameters.MAJOR_BLOCK_TYPE);
        block.setDigest(majorService.getMajor(majorCode).getName());
        block.setCode(majorCode);
        LambdaQueryWrapper<Block> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Block::getType, BlockParameters.FACULTY_BLOCK_TYPE);
        wrapper.eq(Block::getCode, facultyCode);
        block.setPreHash(getOne(wrapper).getMerkleHash());
        return getVoteInfo(block);
    }

    @Override
    public VoteInfo createStudentBlock(String sNo, String schoolCode, String majorCode) {
        Block block = new Block();
        //创建学生区块
        block.setType(BlockParameters.STUDENT_BLOCK_TYPE);
        block.setCode(schoolCode + ":" + sNo);
        LambdaQueryWrapper<Block> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Block::getType, BlockParameters.MAJOR_BLOCK_TYPE);
        wrapper.eq(Block::getCode, majorCode);
        block.setPreHash(getOne(wrapper).getMerkleHash());
        return getVoteInfo(block);
    }

    public VoteInfo getVoteInfo(Block block) {
        block.setCreateTime(new Date());
        //创建投票信息
        VoteInfo voteInfo = new VoteInfo();
        //设置当前区块hash值
        List<String> list = MerkelTreeNodeUtil.getTreeNodeList(block);
        block.setMerkleHash(SimpleMerkleTree.getTreeNodeHash(list));
        //将区块信息放入投票信息中
        voteInfo.setBlock(block);
        voteInfo.setCode(VoteEnum.REQUEST.getCode());
        return voteInfo;
    }

    @Override
    public VoteInfo createAwardBlock(Award award) {
        //创建投票信息
        VoteInfo voteInfo = new VoteInfo();
        //奖项信息->区块的映射blockDto
        BlockDto blockDto = new BlockDto();
        BeanUtils.copyProperties(award, blockDto);
        //创建区块
        Block block = new Block();
        BeanUtils.copyProperties(award, block);
        block.setId(null);
        //设置区块类型、父节点hash值
        LambdaQueryWrapper<Block> wrapper = new LambdaQueryWrapper<>();

        //创建学生区块
        block.setType(BlockParameters.STUDENT_BLOCK_TYPE);
        block.setCode(blockDto.getSNo());
        //获取该学生前一个区块hash
        wrapper.eq(Block::getType, BlockParameters.STUDENT_BLOCK_TYPE);
        wrapper.eq(Block::getCode, blockDto.getSchoolCode() + ":" + blockDto.getSNo());
        wrapper.orderByDesc(Block::getId);
        wrapper.last("limit 1");
        Block b = getOne(wrapper);

        block.setPreHash(b.getMerkleHash());
        //设置前一个奖项的id，用于更新其子区块hash字段
        voteInfo.setId(b.getId());
        //设置当前区块Code
        block.setCode(b.getCode());
        //设置当前区块hash值
        List<String> list = MerkelTreeNodeUtil.getTreeNodeList(block);
        block.setMerkleHash(SimpleMerkleTree.getTreeNodeHash(list));
        //将区块信息放入投票信息中
        voteInfo.setBlock(block);
        return voteInfo;
    }

    @Override
    public boolean haveCode(String code) {

        LambdaQueryWrapper<Block> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Block::getCode, code);
        wrapper.orderByDesc(Block::getId);
        wrapper.last("limit 1");
        return getOne(wrapper) != null;
    }

    @Override
    public boolean haveAward(String digest) {
        LambdaQueryWrapper<Block> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Block::getDigest, digest);
        return getOne(wrapper) != null;
    }
}
